{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "%matplotlib inline\n",
    "import matplotlib\n",
    "import tensorflow as tf\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import scipy.io"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "import claude.utils as cu\n",
    "import claude.tx as tx\n",
    "import claude.claudeflow.systems as cfs\n",
    "import claude.claudeflow.training as cft\n",
    "import claude.claudeflow.helper as cfh\n",
    "import claude.claudeflow.models.SSFstatic as ssf"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "# True:  runs on cluster with GPU etc\n",
    "# False: can run localy without nonlinear impairments\n",
    "runWithNonlinear = False"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "See [`tf_wdmSystem.html`](tf_wdmSystem.html) for version with `runWithNonlinear = True`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "M:\t64\n",
      "nPol:\t2\n",
      "sps:\t16\n",
      "nSamples:\t1024\n",
      "rollOff:\t0.05\n",
      "filterSpan:\t128\n",
      "optimizeP:\tFalse\n",
      "PdBm:\t1\n",
      "Rs:\t32000000000.0\n",
      "channels:\t[-100.  -50.    0.   50.  100.]\n",
      "nChannels:\t5\n",
      "frequencyShift:\tTrue\n",
      "dispersionCompensation:\tFalse\n",
      "beta2:\t2.0999953937404486e-26\n",
      "dz:\t1000000.0\n",
      "Fs:\t512000000000.0\n",
      "N:\t16384\n",
      "realType:\t<dtype: 'float64'>\n",
      "complexType:\t<dtype: 'complex128'>\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# Tx\n",
    "param = cfs.defaultParameters(precision='double')\n",
    "\n",
    "if runWithNonlinear:\n",
    "    param.sps = 16\n",
    "    param.nSamples = 1024\n",
    "    \n",
    "    batch_size = 1\n",
    "    runs = 20\n",
    "    removeSymbols = 32\n",
    "else:\n",
    "    batch_size = 2\n",
    "    runs = 5\n",
    "    removeSymbols = 32\n",
    "    \n",
    "param.M  = 64\n",
    "param.Fs = param.sps * param.Rs\n",
    "print(param)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Fs:\t512000000000.0\n",
      "N:\t16384\n",
      "nSteps:\t2\n",
      "stepSize:\t100\n",
      "ampScheme:\tEDFA\n",
      "noiseEnabled:\tTrue\n",
      "manakovEnabled:\tTrue\n",
      "dispersionCompensationEnabled:\tFalse\n",
      "checkpointInverval:\t2\n",
      "nPol:\t2\n",
      "lambda_:\t1.55003597538907e-06\n",
      "Fc:\t193410000000000.0\n",
      "D:\t16.464\n",
      "alpha:\t0.2\n",
      "beta2:\t2.0999953937404486e-26\n",
      "gamma:\t0\n",
      "nSpans:\t10\n",
      "spanLength:\t100\n",
      "noiseFigure:\t5\n",
      "intType:\t<dtype: 'int32'>\n",
      "realType:\t<dtype: 'float64'>\n",
      "complexType:\t<dtype: 'complex128'>\n",
      "stepSizeTemplate:\t[ 7.52466421 92.47533579]\n",
      "\n"
     ]
    }
   ],
   "source": [
    "ssfParam = ssf.defaultParameters(precision='double')\n",
    "ssfParam.Fs = param.Fs\n",
    "ssfParam.N = param.sps * param.nSamples\n",
    "ssfParam.noiseEnabled = True\n",
    "ssfParam.noiseFigure = 5\n",
    "ssfParam.nSpans = 10\n",
    "\n",
    "if runWithNonlinear:\n",
    "    ssfParam.gamma = 1.3\n",
    "    ssfParam.nSteps = 350\n",
    "else:\n",
    "    ssfParam.gamma = 0\n",
    "    ssfParam.nSteps = 2\n",
    "\n",
    "# ssfParam.stepSize = ssfParam.spanLength/ssfParam.nSteps\n",
    "# ssfParam.stepSizeTemplate = ssfParam.stepSize * np.ones((ssfParam.nSteps,)) # constant stepsize\n",
    "\n",
    "ssfParam.stepSizeTemplate = ssf.logStepSizes(ssfParam.spanLength, ssfParam.alpha, ssfParam.nSteps) # log stepsize\n",
    "\n",
    "print(ssfParam)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "const mean power:  1.0000000000000002\n",
      "const.shape:  (1, 64)\n"
     ]
    }
   ],
   "source": [
    "# Constants\n",
    "c = 299792458\n",
    "constellation = tx.qammod(param.M)\n",
    "print('const mean power: ', np.mean(np.abs(constellation)**2))\n",
    "print('const.shape: ', constellation.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "def run_model(param, ssfParam):\n",
    "    tf.reset_default_graph()\n",
    "    \n",
    "    nDims = 4 # Dimension of X\n",
    "    X = tf.placeholder(tf.float32, shape=(None, param.nChannels, param.nPol, param.nSamples, param.M))\n",
    "    constellation_tf = tf.constant(constellation, param.complexType)\n",
    "\n",
    "    txSymbols = cfh.QAMencoder(X, constellation_tf, realOutput=False)\n",
    "\n",
    "    signal = cfs.wdmTransmitter(txSymbols, param)\n",
    "\n",
    "    ssfParam.stepSize = tf.placeholder(param.realType, shape=(ssfParam.nSpans, ssfParam.nSteps))\n",
    "    signal_out = ssf.model(ssfParam, signal)\n",
    "\n",
    "    param.dispersionCompensation = True\n",
    "    param.beta2  = ssfParam.D * 1e-6 * ( c / ssfParam.Fc )**2 / ( 2 * np.pi * c )\n",
    "    param.dz     = ssfParam.spanLength * 1e3 * ssfParam.nSpans\n",
    "    rxSymbols = cfs.wdmReceiver(signal_out, param)\n",
    "    \n",
    "    #\n",
    "    normP0 = tf.get_default_graph().get_tensor_by_name(\"normP0:0\")\n",
    "    rxSymbols = tf.cast( tf.rsqrt( normP0 ), param.complexType ) * rxSymbols\n",
    "    \n",
    "    # remove beginning and end of symbols\n",
    "    rxSymbols, txSymbols = cfh.truncate(removeSymbols, rxSymbols, txSymbols)\n",
    "\n",
    "    rxSymbols = cfh.staticPhaseRotationCompensation(rxSymbols)\n",
    "    rxSymbols = cfh.testPhases(constellation_tf, txSymbols, rxSymbols, nDims, param.M, nTestPhases=4) \n",
    "    \n",
    "    # metrics    \n",
    "    reduce_axis = [0, 2, 3]\n",
    "    errorrate = cfh.symbolErrorrate(constellation_tf, txSymbols, rxSymbols, nDims, param.M, reduce_axis)\n",
    "    \n",
    "    one = tf.constant( 1, param.realType )\n",
    "    effSNR = cfh.effectiveSNR(txSymbols, rxSymbols, one, reduce_axis)\n",
    "\n",
    "    # MI\n",
    "    MI = []\n",
    "    for (txChannel, rxChannel) in zip(tf.split(txSymbols, param.nChannels, axis=1), tf.split(rxSymbols, param.nChannels, axis=1)):\n",
    "        MI_temp = cfh.gaussianMI(tf.reshape(txChannel,[-1]), tf.reshape(rxChannel,[-1]), constellation_tf, param.M)\n",
    "        MI.append(MI_temp)\n",
    "\n",
    "    MI = tf.stack(MI)    \n",
    "    MI = tf.identity( MI, name='MI' )\n",
    "\n",
    "    # only mid channel\n",
    "    midChannel = param.nChannels//2 +1\n",
    "    errorrate = errorrate[midChannel]\n",
    "    MI = MI[midChannel]\n",
    "    effSNR = effSNR[midChannel]\n",
    "    \n",
    "    metricsDict = {'errorrate':errorrate, 'MI': MI, 'effSNR': effSNR}    \n",
    "    meanMetricOpsDict, updateOps, resetOps = cft.create_mean_metrics(metricsDict)\n",
    "    \n",
    "    init = tf.global_variables_initializer()\n",
    "\n",
    "    sess = tf.Session()\n",
    "    sess.run(init)\n",
    "\n",
    "    sess.run(resetOps)\n",
    "    for mcRun in range(runs):\n",
    "        print(mcRun, end=' ', flush=True)\n",
    "        randomisedStepSize = ssf.randomizeSteps(ssfParam.stepSizeTemplate, ssfParam.spanLength, ssfParam.nSpans)\n",
    "        x, idx, x_seed = cu.hotOnes((batch_size, param.nChannels, param.nPol, param.nSamples),(1,2,3,4,0),param.M)\n",
    "        feedDict = { X:x, ssfParam.stepSize:randomisedStepSize }\n",
    "        sess.run(updateOps, feed_dict=feedDict)\n",
    "    \n",
    "    outMetrics = sess.run(list(meanMetricOpsDict.values()), feed_dict=feedDict)\n",
    "    outMetrics = { key:val for key,val in zip(list(meanMetricOpsDict.keys()), outMetrics) }\n",
    "    \n",
    "    outString = ''\n",
    "    for key, value in outMetrics.items():\n",
    "        outString += ' - {}: {:.4f}'.format(key, value)\n",
    "    print(outString, flush=True)\n",
    "\n",
    "    sess.close()\n",
    "    print(' ')\n",
    "    return outMetrics['errorrate'], outMetrics['MI'], outMetrics['effSNR'], sess, feedDict"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "PdBm: -8 - nSpans: 10, nSteps: 2\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "WARNING: Logging before flag parsing goes to stderr.\n",
      "W0923 22:48:02.630471 139908752721728 lazy_loader.py:50] \n",
      "The TensorFlow contrib module will not be included in TensorFlow 2.0.\n",
      "For more information, please see:\n",
      "  * https://github.com/tensorflow/community/blob/master/rfcs/20180907-contrib-sunset.md\n",
      "  * https://github.com/tensorflow/addons\n",
      "  * https://github.com/tensorflow/io (for I/O related ops)\n",
      "If you depend on functionality not listed there, please file an issue.\n",
      "\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0 1 2 3 4  - errorrate: 0.6283 - MI: 3.5051 - effSNR: 10.8522\n",
      " \n",
      "PdBm: -6 - nSpans: 10, nSteps: 2\n",
      "0 1 2 3 4  - errorrate: 0.4993 - MI: 4.0806 - effSNR: 12.9168\n",
      " \n",
      "PdBm: -4 - nSpans: 10, nSteps: 2\n",
      "0 1 2 3 4  - errorrate: 0.3604 - MI: 4.6328 - effSNR: 14.8245\n",
      " \n",
      "PdBm: -2 - nSpans: 10, nSteps: 2\n",
      "0 1 2 3 4  - errorrate: 0.2181 - MI: 5.1740 - effSNR: 16.8112\n",
      " \n",
      "PdBm: 0 - nSpans: 10, nSteps: 2\n",
      "0 1 2 3 4  - errorrate: 0.0952 - MI: 5.6208 - effSNR: 18.8259\n",
      " \n",
      "PdBm: 2 - nSpans: 10, nSteps: 2\n",
      "0 1 2 3 4  - errorrate: 0.0289 - MI: 5.8813 - effSNR: 20.7779\n",
      " \n",
      "PdBm: 4 - nSpans: 10, nSteps: 2\n",
      "0 1 2 3 4  - errorrate: 0.0052 - MI: 5.9784 - effSNR: 22.7118\n",
      " \n"
     ]
    }
   ],
   "source": [
    "powerSweep = np.arange(-8, 4+1, 2)\n",
    "SSFeffSNR = np.zeros(powerSweep.shape)\n",
    "SSFMI = np.zeros(powerSweep.shape)\n",
    "sess = 0\n",
    "feedDict = 0\n",
    "for ii, PdBm in enumerate(powerSweep):\n",
    "    print('PdBm: {}'.format(PdBm), end=' - ')\n",
    "    param.PdBm = PdBm\n",
    "    (avErrorrate, avMI, avEffSNR, sess, feedDict) = run_model(param, ssfParam)\n",
    "    SSFeffSNR[ii] = avEffSNR\n",
    "    SSFMI[ii] = avMI"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "import claude.models.NLIN as nlin\n",
    "# System parameters\n",
    "qamParam = nlin.defaultParameters()\n",
    "qamParam.nSpans = ssfParam.nSpans\n",
    "# qamParam.gamma = ssfParam.gamma"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "aseNoisePower, interConst, intraConst, interConstAdd, intraConstAdd = nlin.calcConstants(qamParam)\n",
    "nlinPowerSweep = np.arange(-8, 4+1, 0.1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "# QAM\n",
    "qam_constellation = np.squeeze(tx.qammod(param.M))\n",
    "qamParam.kur, qamParam.kur3 = nlin.calcKur(qam_constellation)\n",
    "qamEffSNR = nlinPowerSweep - nlin.calcNLIN(qamParam, nlinPowerSweep, aseNoisePower, interConst, intraConst, interConstAdd, intraConstAdd)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.plot(nlinPowerSweep, qamEffSNR, 'b')\n",
    "plt.plot(powerSweep, SSFeffSNR, 'xr')\n",
    "plt.title('Power [dBm] VS effective SNR')\n",
    "plt.xlabel('Power [dBm]')\n",
    "plt.ylabel('effective SNR [dB]')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "qamMI = np.zeros(np.shape(qamEffSNR))\n",
    "N = 5e4\n",
    "\n",
    "for ii,p in enumerate(nlinPowerSweep):\n",
    "    qamMI[ii] = cu.SNRtoMI(N, qamEffSNR[ii], np.expand_dims(qam_constellation, 0))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.plot(nlinPowerSweep, qamMI, 'b')\n",
    "plt.plot(powerSweep, SSFMI, 'xr')\n",
    "plt.title('Power [dBm] VS MI')\n",
    "plt.xlabel('Power [dBm]')\n",
    "plt.ylabel('MI [bits]')\n",
    "plt.show()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
